package com.hfut.eeg.socket;

import cn.hutool.core.lang.Console;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hfut.eeg.common.component.EEGLocalFileReader;
import com.hfut.eeg.common.component.Receivecache;
import com.hfut.eeg.dto.EerWaves;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
@Scope("singleton")
public class AiServer implements Runnable{
    private static final Logger LOGGER = LoggerFactory.getLogger(AiServer.class);
    @Autowired
    SendToClient sendToClient;

    @Autowired
    GetFromClient getFromClient;

    @Autowired
    private EEGLocalFileReader eegLocalFileReader;

    @Value("${AiServer.address}")
    private String address;

    @Value("${AiServer.port}")
    private int port;


    Socket socket;
    InputStream inputStream;
    OutputStream outputStream;

    //获取信息的缓存池
    private ArrayList<ArrayList<ArrayList>>cachePools = new ArrayList<>();
    //异常波数量
    private int errNum;
    //当前病人的eegId
    String eegId = null;

    //当前病人产生的eeg波数量，用于计算实际异常波位置
    private volatile int eegNum=0;

    public AiServer(){}


    public ArrayList<ArrayList<ArrayList>> getCachePools() {
        return cachePools;
    }

    public void setEegId(String eegId) {
        this.eegId = eegId;
    }

    public int getErrNum() {
        return errNum;
    }

    public void setErrNum(int errNum) {
        this.errNum = errNum;
    }

    public String getEegId() {
        return eegId;
    }

    public synchronized void setCachePools(ArrayList<ArrayList> cachePools) {
        //每次意味着新的一组数据来临，进行++
        eegNum++;
        this.cachePools.add(cachePools);
    }

    public int getEegNum() {
        return eegNum;
    }

    public synchronized void setEegNum(int eegNum) {
        this.eegNum = eegNum;
    }

    public void reset(){
        setErrNum(0);
        setEegId(null);
        setEegNum(0);
        cachePools.clear();
    }

    /**
     * 从客户端获取数据的线程实现
     */
    @Component
    @Scope("singleton")
    private class GetFromClient implements  Runnable {
        public GetFromClient() {
        }

        @Autowired
        Receivecache receivecache;

        private synchronized void setFft(JSONArray jsonArray) {
            ArrayList<ArrayList> lists = new ArrayList<>();
            for (int i = 0; i < 16; i++) {
                List list = JSON.parseArray(jsonArray.getString(i), Float.class);
                lists.add((ArrayList) list);
            }
            receivecache.addFftToPool(lists, eegId);
        }

        private synchronized void setErrWaves(JSONArray errWaves) {
            ArrayList<EerWaves> arrayList = new ArrayList<>();
            for (int i = 0; i < errWaves.size(); i++) {
                Integer startWaves = errWaves.getJSONObject(i).getInteger("beginWave");
                Integer endWaves = errWaves.getJSONObject(i).getInteger("endWave");
                startWaves = startWaves+eegNum*500<0?0:startWaves+eegNum*500;
                endWaves = endWaves+eegNum*500;
                arrayList.add(new EerWaves(System.currentTimeMillis(), eegId, startWaves,
                        endWaves, errWaves.getJSONObject(i).getString("message"),
                        errWaves.getJSONObject(i).getInteger("errRank"), errWaves.getJSONObject(i).getInteger("channelIndex")));
            }
            receivecache.addErrWavesToPool(arrayList);
            //eerWavesService.insertEerWaves(arrayList);
        }

        private synchronized void setErrNum(int ErrNum) {
            errNum += ErrNum;
        }

        private synchronized void setBrainChannel(int[][] brainChannel) {
            ArrayList<ArrayList> lists = new ArrayList<>();
            for (int i = 0; i < 16; i++) {
                ArrayList arrayList = new ArrayList();
                arrayList.add(brainChannel[i][0]);
                lists.add(arrayList);
            }
            receivecache.addBrainChannel(lists);
        }

        private synchronized void setEnergy(JSONArray energy) {
            ArrayList arr = new ArrayList();
            if(energy==null||energy.size()==0)
                return;
            for (int i = 0; i < energy.size(); i++) {
                StringBuilder tmp = new StringBuilder(energy.getString(i));
                if (tmp.indexOf("[") < 0) {
                    tmp = tmp.insert(0, "[");
                    tmp = tmp.insert(tmp.length(), "]");
                }
                List list = new ArrayList();
                try {
                    list = JSON.parseArray(tmp.toString(), Float.class);
                }catch (Exception e){
                    e.printStackTrace();
                    list.add(0f);
                }
                arr.add(list);
            }
            receivecache.addEnergyChannel(arr);
        }


        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1);

                    byte[] bytes = new byte[10240];
                    byte[]contents = new byte[10240000];
                    int len = inputStream.read(bytes);
                    int contentLen = byteArrayToInt(Arrays.copyOfRange(bytes,0,4));
                    int sum =len;
                    System.arraycopy(bytes,0,contents,0,len);
                    while(sum<(contentLen+4)){
                        len = inputStream.read(bytes);
                        try{
                            System.arraycopy(bytes,0,contents,sum,len);
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                        sum+=len;
                    }
                    if (sum==contentLen+4) {
                        byte[] res = Arrays.copyOfRange(contents,4,contentLen+4);
                        JSONObject receiveInformation = (JSONObject) JSONObject.parse(res);
                        Console.log(receiveInformation);
                        //获取状态码
                        Integer code = receiveInformation.getInteger("code");
                        //获取相应信息
                        String message = receiveInformation.getString("message");
                        //获取具体信息的content
                        JSONObject content = receiveInformation.getJSONObject("content");
                        //JSONObject content = new JSONObject();
                        //获取fft变换的数组
                        com.alibaba.fastjson.JSONArray fft = content.getJSONArray("fft");
                        //获取异常波的信息
                        com.alibaba.fastjson.JSONArray errWaves = content.getJSONArray("errWaves");
                        //获取一个  包含五个数的数组
                        com.alibaba.fastjson.JSONArray energy = content.getJSONArray("energy");
                        //获取异常波的数量
                        int errNum = errWaves.size();
                        //保存通道的脑部能量
                        int[][] brainChannel = new int[17][1];
                        //对脑部能量进行获取
                        for (int i = 0; i < errNum; i++) {
                            brainChannel[errWaves.getJSONObject(i).getInteger("channelIndex")][0]++;
                        }
                        while (eegId == null) {
                            Thread.sleep(1);
                        }
                        setErrWaves(errWaves);
                        setErrNum(errNum);
                        setEnergy(energy);
                        setBrainChannel(brainChannel);
                        setFft(fft);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 字节数组转int
     */

    public static int byteArrayToInt(byte[] b) {
        return   b[3] & 0xFF |
                (b[2] & 0xFF) << 8 |
                (b[1] & 0xFF) << 16 |
                (b[0] & 0xFF) << 24;
    }


    /**
     * 进行个数转化，把Object进行转化为bytes数组，这里返回一个map
     */
    public Map<String, Object> toByteArray (String obj) {
        byte[] bytes = obj.getBytes();
        Integer i = bytes.length;
        byte[] content = new byte[i+4];
        byte[] header=ByteBuffer.allocate(4).putInt(i).array();
        header = Arrays.copyOfRange(header,0,4);
        System.arraycopy(header,0,content,0,header.length);
        System.arraycopy(bytes,0,content,4,bytes.length);
        Map<String,Object> map = new HashMap<>();
        map.put("count",content.length);
        map.put("bytes",content);
        return map;
    }




    /**
     * 向服务器发送数据的接口，
     * 抛弃原有的SocketChannel方式
     */
    @Component
    @Scope("singleton")
    private class SendToClient implements Runnable {

        public SendToClient() {
        }
        @Override
        public void run() {
            eegLocalFileReader.setAiPrepared(true);
            Long startTime = 0L;
            while (true) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (outputStream != null && cachePools != null) {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Iterator<ArrayList<ArrayList>> iterator = cachePools.iterator();
                    int index = 0;
                    while (iterator.hasNext() && index<cachePools.size()) {
                        Long endTime = System.currentTimeMillis();
                        if(endTime-startTime < 900){
                            try {
                                Thread.sleep(950-(endTime-startTime));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        ArrayList<ArrayList> arrayList = cachePools.get(index);
                        Console.log(arrayList.get(0).size());
                        arrayList.remove(arrayList.size() - 1);
                        arrayList.remove(arrayList.size() - 1);
                        Console.log(arrayList.size());
                        //进行封装成Map
                        if(arrayList==null || arrayList.size()!=16 || arrayList.get(0).size()!=500){
                            cachePools.remove(0);
                            index++;
                            startTime = System.currentTimeMillis();
                            continue;
                        }
                        HashMap<String, Object> json = new HashMap<>();
                        json.put("timeStamp", df.format(new Date()));
                        json.put("data", cachePools.get(index));
                        String jsonObject = JSON.toJSONString(json);
                        Console.log(jsonObject);
                        //把这个对象转化为字节码
                        //要先转二进制流，再在前面加，不是转成map
                        Map<String, Object> map = toByteArray(jsonObject);
                        //获取信息的大小，分配缓冲区
                        int count = (Integer) map.get("count");
                        ByteBuffer byteBuffer = ByteBuffer.allocate(count);
                        byte[] bytes = (byte[]) map.get("bytes");

                        try {
                            outputStream.write(bytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        System.out.println("sendToClient count:" + count);
                        cachePools.remove(0);
                        index++;
                        startTime = System.currentTimeMillis();
                    }
                }
            }
        }
    }

    /**
    * @Description: 重启服务的方法
    * @param
    * @return
    * @author 梁琦
    * @date 2019-12-18 14:03
    * @throws
    */
    public boolean restart(){
        return false;
    }


    /**
     * 表示java服务器这边的启动方法
     */
    @Override
    public void run() {
        try{
            socket = new Socket(address,port);
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            new Thread(sendToClient).start();
            new Thread(getFromClient).start();
            while(true){
                Thread.sleep(1);
                if(!socket.isConnected()){
                    socket = new Socket(address,port);
                    inputStream = socket.getInputStream();
                    outputStream = socket.getOutputStream();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
